#pragma once
#include <string>
#include <jsoncpp/json/json.h>
#include "../comm/util.hpp"
#include "compiler.hpp"
#include "runner.hpp"

class CompilerAndRun
{
public:
    static void RemoveTempFiles(const std::string& file_name)
    {
        // 六个文件
        std::string src_file = PathUtil::PathSrc(file_name);
        if (FileUtil::IsFileExists(src_file))
        {
            unlink(src_file.c_str());
        }

        std::string cmp_file = PathUtil::PathErr(file_name);
        if (FileUtil::IsFileExists(cmp_file))
        {
            unlink(cmp_file.c_str());
        }

        std::string exe_file = PathUtil::PathExe(file_name);
        if (FileUtil::IsFileExists(exe_file))
        {
            unlink(exe_file.c_str());
        }

        std::string stdin_file = PathUtil::Stdin(file_name);
        if (FileUtil::IsFileExists(stdin_file))
        {
            unlink(stdin_file.c_str());
        }

        std::string stdout_file = PathUtil::Stdout(file_name);
        if (FileUtil::IsFileExists(stdout_file))
        {
            unlink(stdout_file.c_str());
        }

        std::string stderr_file = PathUtil::Stderr(file_name);
        if (FileUtil::IsFileExists(stderr_file))
        {
            unlink(stderr_file.c_str());
        }
    }

    static std::string CodeToDesc(int code, const std::string& file_name)
    {
        std::string desc;
        switch (code)
        {
        case 0:         
            desc = "运行成功";
            break;
        case -1:
            desc = "提交内容为空";
            break;
        case -2:
            desc = "未知错误";
            break;
        case -3:
            // 原因读编译报错文件
            FileUtil::ReadFile(PathUtil::PathErr(file_name), &desc, true);
        break;
        case SIGABRT:   //6
            desc = "内存超出范围";
            break;
            case SIGXCPU:   //24
        desc = "cpu超时";
            break;
        case SIGFPE:    //8
        desc = "浮点溢出";
            break;
        default:
            desc = "未知错误：" + std::to_string(code);
            break;
        }

        return desc;
    }
    /****************************************************
     * 输入：
     * code: 用户提交的代码
     * input: 代码对应的输入参数，不做处理
     * cpu_limit: 时间要求
     * mem_limit: 空间要求
     * 输出：
     * 必填
     * status: 状态码
     * reason: 请求结果
     * 选填
     * stdout: 程序运行结果
     * stderr: 程序运行的错误结果
     * 协议格式：
     * in_json:{"code":"int main.."， "input":"", cpu_limit, mem_limit}
     * outjson:{status: -1/2/3, reason: , stdout: ,stderr: }
     ****************************************************/
    static void Start(const std::string& in_json, std::string* out_json)
    {
        // 转换为json格式
        Json::Value in_value;
        Json::Reader reader;
        reader.parse(in_json, in_value);

        std::string code = in_value["code"].asString();
        std::string input = in_value["input"].asString();
        int cpu_limit = in_value["cpu_limit"].asInt();
        int mem_limit = in_value["mem_limit"].asInt();

        // 返回的变量
        int status = 0;
        int result = 0;
        Json::Value out_value;
        std::string file_name;
        // 状态码 -1 表示内容空
        if (code.empty())
        {
            status = -1;
            goto END;
        }

        // 读取代码，形成文件
        // 时间戳+原子递增唯一值形成唯一文件
        file_name = FileUtil::UniqueName();
        // 写入文件
        if (!FileUtil::WriteFile(PathUtil::PathSrc(file_name), code))
        {
            status = -2;    // 未知错误
            goto END;
        }
        // 编译
        if (!Compiler::Compile(file_name))
        {
            status = -3;    // 编译错误
            goto END;
        }
        // 运行，分三种情况
        result = Runner::Run(file_name, cpu_limit, mem_limit);
        if (result < 0)
        {
            status = -2;    // 未知错误
        }
        else if (result > 0)
        {
            // 程序崩溃
            status = result;  // 返回信号
        }
        else
        {
            status = 0;
        }
END:
        // 构建返回json
        out_value["status"] = status;
        out_value["reason"] = CodeToDesc(status, file_name);
        if (status == 0)
        {
            // 整个过程全部成功，补充运行结果和运行错误文件
            std::string stdout_file;
            FileUtil::ReadFile(PathUtil::Stdout(file_name), &stdout_file, true);
            out_value["stdout"] = stdout_file;

            std::string stderr_file;
            FileUtil::ReadFile(PathUtil::Stderr(file_name), &stderr_file, true);
            out_value["stderr"] = stderr_file;
        }

        Json::StyledWriter writer;
        *out_json = writer.write(out_value);
        // 移除临时文件
        RemoveTempFiles(file_name);
    }
};